<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Servicio de Carga y Descarga de Archivos</title>
    <!-- CSS样式定义开始 -->
    <style>
      /* 页面主体样式 */
      body {
        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        max-width: 800px;
        margin: 0 auto;
        padding: 20px;
        line-height: 1.6;
      }
      /* 标题样式 */
      h1 {
        color: #333;
        text-align: center;
        margin-bottom: 30px;
      }
      /* 卡片容器样式 */
      .card {
        background-color: #f8f9fa;
        border-radius: 8px;
        padding: 20px;
        margin-bottom: 20px;
        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
      }
      /* 文件表单样式 */
      .file-form {
        display: flex;
        flex-direction: column;
        gap: 10px;
      }
      /* 按钮基本样式 */
      .btn {
        background-color: #4caf50;
        color: white;
        padding: 10px 15px;
        border: none;
        border-radius: 4px;
        cursor: pointer;
        font-size: 16px;
        transition: background-color 0.3s;
      }
      /* 按钮悬停效果 */
      .btn:hover {
        background-color: #45a049;
      }
      /* 次要按钮样式 */
      .btn-secondary {
        background-color: #6c757d;
      }
      /* 次要按钮悬停效果 */
      .btn-secondary:hover {
        background-color: #5a6268;
      }
      /* 进度条样式 */
      progress {
        width: 100%;
        height: 20px;
        margin-top: 10px;
      }
      /* 文件列表样式 */
      .file-list {
        list-style: none;
        padding: 0;
      }
      /* 文件项样式 */
      .file-item {
        display: flex;
        flex-direction: column;
        padding: 10px;
        border-bottom: 1px solid #ddd;
      }
      /* 文件项下载状态区域 */
      .download-status {
        margin-top: 5px;
        font-size: 0.9em;
        color: #666;
      }
      .file-item-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        width: 100%;
      }
      /* 最后一个文件项无底部边框 */
      .file-item:last-child {
        border-bottom: none;
      }
      /* 文件信息容器 */
      .file-info {
        display: flex;
        flex-direction: column;
      }
      /* 文件名样式 */
      .file-name {
        font-weight: bold;
      }
      /* 文件大小样式 */
      .file-size {
        color: #6c757d;
        font-size: 0.9em;
      }
      /* 文件操作按钮容器 */
      .file-actions {
        display: flex;
        gap: 10px;
      }
      /* 提示信息样式 */
      .info-text {
        font-size: 0.9em;
        color: #666;
        margin-top: 5px;
      }
      /* 分片下载进度条容器 */
      .chunk-progress-container {
        margin-top: 5px;
        display: none;
      }
      /* 分片进度条 */
      .chunk-progress {
        width: 100%;
        height: 20px;
        margin-bottom: 5px;
        position: relative;
      }
      /* 分片进度显示 */
      .chunk-label {
        position: absolute;
        left: 50%;
        transform: translateX(-50%);
        color: #333;
        font-size: 12px;
        line-height: 20px;
      }
      /* 下载速度显示 */
      .download-speed {
        font-size: 0.8em;
        color: #666;
        margin-top: 5px;
      }
      /* 暂停/继续按钮 */
      .pause-resume-btn {
        background-color: #ffc107;
      }
      .pause-resume-btn:hover {
        background-color: #e0a800;
      }
      /* 下载耗时显示 */
      .download-time {
        font-size: 0.8em;
        color: #666;
        margin-top: 5px;
      }
      /* 下载统计面板 */
      .download-stats {
        margin-top: 10px;
        padding: 10px;
        background-color: #f0f0f0;
        border-radius: 4px;
        display: none;
      }
    </style>
    <!-- CSS样式定义结束 -->
    <!-- 引入jQuery -->
    <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
  </head>
  <body>
    <!-- 页面标题 -->
    <h1>Servicio de Carga y Descarga de Archivos</h1>

    <!-- 文件上传区域 -->
    <div class="card">
      <h2>Cargar Archivo</h2>
      <form id="uploadForm" class="file-form">
        <!-- 文件选择输入框 -->
        <input type="file" id="fileInput" name="file" required />
        <!-- 上传按钮 -->
        <button type="submit" class="btn">Subir Archivo</button>
        <!-- 上传进度条，初始隐藏 -->
        <progress id="uploadProgress" value="0" max="100" style="display: none"></progress>
        <!-- 上传状态显示区域 -->
        <div id="uploadStatus"></div>
        <p class="info-text">✅ Permitidos archivos de hasta 1GB</p>
      </form>
    </div>

    <!-- 文件列表显示区域 -->
    <div class="card">
      <h2>Archivos Disponibles</h2>
      <!-- 刷新列表按钮 -->
      <button id="refreshButton" class="btn btn-secondary">Actualizar Lista</button>
      <!-- 文件列表容器 -->
      <div id="fileListContainer">
        <ul id="fileList" class="file-list">
          <li>Cargando archivos...</li>
        </ul>
        <!-- 分片下载进度显示区域 -->
        <div id="chunkProgressContainer" class="chunk-progress-container">
          <h3>下载进度</h3>
          <div id="chunkProgressList"></div>
          <div class="download-speed" id="downloadSpeed"></div>
          <div class="download-time" id="downloadTime"></div>
          <button class="btn pause-resume-btn" id="pauseResumeBtn">暂停</button>
        </div>
      </div>
    </div>

    <!-- JavaScript代码开始 -->
    <script>
      // ================ 全局变量和常量定义 ================
      // 定义分片大小为2MB
      const CHUNK_SIZE = 1024 * 1024 * 2;
      // 定义最大并发下载分片数
      const MAX_CONCURRENT_CHUNKS = 3;
      // 存储当前活动的下载任务，使用Map来跟踪不同文件的下载状态
      let activeDownloads = new Map();

      // ================ 工具函数 ================
      /**
       * 格式化文件大小，将字节数转换为人类可读的格式
       * @param {number} bytes - 文件大小（字节）
       * @returns {string} 格式化后的文件大小（如：1.5 MB）
       */
      function formatFileSize(bytes) {
        if (bytes === 0) return '0 Bytes';
        const k = 1024;
        const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
        const i = Math.floor(Math.log(bytes) / Math.log(k));
        return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
      }

      /**
       * 更新下载速度显示
       * @param {object} downloadState - 下载状态对象
       */
      function updateDownloadSpeed(downloadState) {
        const elapsed = (Date.now() - downloadState.startTime) / 1000;
        const speed = downloadState.downloadedSize / elapsed;
        const speedText = formatFileSize(speed) + '/s';
        document.getElementById('downloadSpeed').textContent = `下载速度: ${speedText}`;
      }

      /**
       * 格式化时间，将毫秒转换为友好的时间格式
       * @param {number} milliseconds - 毫秒数
       * @returns {string} 格式化后的时间字符串
       */
      function formatTime(milliseconds) {
        if (milliseconds < 1000) {
          return `${milliseconds}毫秒`;
        }
        const seconds = Math.floor(milliseconds / 1000);
        const minutes = Math.floor(seconds / 60);
        const remainingSeconds = seconds % 60;
        if (minutes > 0) {
          return `${minutes}分${remainingSeconds}秒`;
        }
        return `${seconds}秒`;
      }

      // ================ 下载队列管理 ================
      /**
       * 全局下载队列管理器
       * 负责控制并发下载数量，确保不会同时进行太多下载任务
       */
      const downloadQueue = {
        // 最大同时下载文件数
        maxConcurrent: 2,
        // 当前正在进行的下载任务集合
        running: new Set(),
        // 等待下载的任务队列
        waiting: [],

        /**
         * 添加下载任务到队列
         * @param {Function} downloadTask - 下载任务函数
         * @returns {Promise} 下载完成的Promise
         */
        async add(downloadTask) {
          if (this.running.size >= this.maxConcurrent) {
            // 如果当前运行的任务数达到上限，加入等待队列
            await new Promise((resolve) => {
              this.waiting.push(() => {
                resolve();
                this.running.add(downloadTask);
                return downloadTask();
              });
            });
          } else {
            // 直接执行任务
            this.running.add(downloadTask);
            await downloadTask();
          }

          // 任务完成后的处理
          this.running.delete(downloadTask);
          if (this.waiting.length > 0) {
            // 如果有等待的任务，执行下一个
            const next = this.waiting.shift();
            next();
          }
        },
      };

      // ================ 分片下载管理类 ================
      /**
       * 分片下载管理器类 - jQuery实现
       */
      class ChunkDownloadManager {
        constructor(filename, fileSize, statusElement) {
          this.filename = filename;
          this.fileSize = fileSize;
          this.$statusElement = $(statusElement);
          this.chunks = [];
          this.downloaded = new Set();
          this.retries = new Map();
          this.maxRetries = 3;
          this.paused = false;
          this.aborted = false;
          this.startTime = Date.now();
          this.downloadedSize = 0;
          this.chunkStreams = new Map();

          // 创建并初始化进度显示容器
          this.$progressList = $('<div>', {
            id: `progress-${encodeURIComponent(filename).replace(/%/g, '_')}`,
            class: 'chunk-progress-container',
            css: { display: 'block' },
          });
          this.$statusElement.append(this.$progressList);
        }

        async start() {
          const chunkSize = Math.min(CHUNK_SIZE, Math.ceil(this.fileSize / 10));
          for (let start = 0; start < this.fileSize; start += chunkSize) {
            const end = Math.min(start + chunkSize - 1, this.fileSize - 1);
            this.chunks.push({ start, end });
          }

          this.setupUI();
          await this.downloadChunks();
        }

        setupUI() {
          const chunkSize = Math.min(CHUNK_SIZE, Math.ceil(this.fileSize / 10));
          const totalChunks = Math.ceil(this.fileSize / chunkSize);

          // 创建所有分片的进度条
          for (let i = 0; i < totalChunks; i++) {
            const safeFileName = encodeURIComponent(this.filename).replace(/%/g, '_');
            const $progressBar = $('<div>', { class: 'chunk-progress' }).append(
              $('<progress>', {
                value: 0,
                max: 100,
                id: `chunk-${safeFileName}-${i}`,
              }),
              $('<span>', {
                class: 'chunk-label',
                id: `chunk-label-${safeFileName}-${i}`,
                text: `分片 ${i + 1}: 0%`,
              }),
            );
            this.$progressList.append($progressBar);
          }

          // 添加暂停/继续按钮
          const $pauseResumeBtn = $('<button>', {
            class: 'btn pause-resume-btn',
            text: '暂停',
          }).on('click', () => {
            this.paused = !this.paused;
            $pauseResumeBtn.text(this.paused ? '继续' : '暂停');
          });

          // 添加中止按钮
          const $abortBtn = $('<button>', {
            class: 'btn btn-danger',
            text: '中止下载',
            css: {
              backgroundColor: '#dc3545',
              marginLeft: '10px',
            },
          }).on('click', () => this.abort());

          // 添加下载状态显示区域
          const $downloadStats = $('<div>', {
            class: 'download-stats',
            css: { display: 'block' },
          }).append(
            $('<div>', { class: 'download-speed' }),
            $('<div>', { class: 'download-time' }),
          );

          this.$progressList.append($pauseResumeBtn, $abortBtn, $downloadStats);
        }

        abort() {
          this.aborted = true;
          this.paused = true;
          this.chunkStreams.forEach((stream) => stream.cancel());
          this.chunkStreams.clear();
          this.cleanup();
        }

        cleanup() {
          this.chunks.forEach((_, index) => {
            if (this.downloaded.has(index)) {
              URL.revokeObjectURL(this.chunks[index]);
              this.chunks[index] = null;
            }
          });
          this.$progressList.remove();
          this.chunks = [];
          this.downloaded.clear();
          this.chunkStreams.clear();
        }

        // 下载分片
        async downloadChunks() {
          try {
            const concurrentChunks = 3;
            let activeDownloads = 0;
            let nextChunkIndex = 0;

            while (nextChunkIndex < this.chunks.length && !this.aborted) {
              if (this.paused) {
                await new Promise((resolve) => setTimeout(resolve, 1000));
                continue;
              }

              while (activeDownloads < concurrentChunks && nextChunkIndex < this.chunks.length) {
                const index = nextChunkIndex++;
                if (!this.downloaded.has(index)) {
                  activeDownloads++;
                  this.downloadChunk(index, this.chunks[index]).finally(() => {
                    activeDownloads--;
                  });
                }
              }

              await new Promise((resolve) => setTimeout(resolve, 100));
            }

            if (!this.aborted && this.downloaded.size === this.chunks.length) {
              await this.mergeAndDownload();
            }
          } catch (error) {
            console.error('Download failed:', error);
            this.$statusElement.text('下载失败，请重试');
          } finally {
            this.cleanup();
          }
        }

        // 下载单个分片
        async downloadChunk(index, { start, end }) {
          if (this.aborted) return;

          const retryCount = this.retries.get(index) || 0;
          if (retryCount >= this.maxRetries) {
            throw new Error(`分片 ${index + 1} 下载失败次数过多`);
          }

          try {
            const response = await fetch(`/files/chunk-download/${this.filename}`, {
              headers: { Range: `bytes=${start}-${end}` },
            });

            if (!response.ok) throw new Error('Chunk download failed');

            const reader = response.body.getReader();
            const stream = new ReadableStream({
              async start(controller) {
                try {
                  while (true) {
                    const { done, value } = await reader.read();
                    if (done) break;
                    controller.enqueue(value);
                  }
                  controller.close();
                } catch (error) {
                  controller.error(error);
                }
              },
            });

            this.chunkStreams.set(index, stream);
            const blob = await new Response(stream).blob();
            this.chunkStreams.delete(index);

            // 使用临时URL存储blob
            const url = URL.createObjectURL(blob);
            this.chunks[index] = url;
            this.downloaded.add(index);
            this.downloadedSize += blob.size;
            this.updateProgress(index, 100);
          } catch (error) {
            console.error(`分片 ${index + 1} 下载失败:`, error);
            this.retries.set(index, retryCount + 1);
            if (retryCount < this.maxRetries) {
              await new Promise((resolve) => setTimeout(resolve, 1000 * (retryCount + 1)));
              return this.downloadChunk(index, { start, end });
            }
            throw error;
          }
        }

        // 合并并下载
        async mergeAndDownload() {
          try {
            const blobs = await Promise.all(
              this.chunks.map(async (url, index) => {
                if (url) {
                  const response = await fetch(url);
                  const blob = await response.blob();
                  URL.revokeObjectURL(url); // 释放URL
                  this.chunks[index] = null; // 清除引用
                  return blob;
                }
                return null;
              }),
            );

            const finalBlob = new Blob(blobs.filter(Boolean));
            blobs.length = 0; // 清除数组引用

            const url = URL.createObjectURL(finalBlob);
            const a = document.createElement('a');
            a.href = url;
            a.download = this.filename;
            document.body.appendChild(a);

            // 记录完成时间并更新状态
            const endTime = Date.now();
            const duration = endTime - this.startTime;
            const timeText = formatTime(duration);
            const statusText = `下载完成 | 总耗时: ${timeText}`;

            // 创建持久的状态显示
            const statusDiv = document.createElement('div');
            statusDiv.className = 'download-status';
            statusDiv.textContent = statusText;
            this.$statusElement.html(''); // 清除之前的状态
            this.$statusElement.append(statusDiv);

            // 触发下载
            a.click();
            document.body.removeChild(a);

            // 延迟释放资源
            setTimeout(() => {
              URL.revokeObjectURL(url);
              this.cleanup();
            }, 1000);
          } catch (error) {
            console.error('Error merging file:', error);
            this.$statusElement.text('合并文件失败，请重试');
          }
        }

        // 更新进度显示
        updateProgress(index, percent) {
          const safeFileName = encodeURIComponent(this.filename).replace(/%/g, '_');
          $(`#chunk-${safeFileName}-${index}`).val(percent);
          $(`#chunk-label-${safeFileName}-${index}`).text(
            `分片 ${index + 1}: ${percent.toFixed(1)}%`,
          );
        }
      }

      // 开始多线程下载（更新）
      async function startMultiThreadedDownload(filename, fileSize, downloadStatusElement) {
        // 如果已经在下载，返回
        if (activeDownloads.has(filename)) {
          alert('该文件已在下载中');
          return;
        }

        // 初始化下载状态
        const downloadState = {
          chunks: [],
          downloaded: new Set(),
          paused: false,
          startTime: Date.now(),
          totalSize: fileSize,
          downloadedSize: 0,
          statusElement: downloadStatusElement,
        };
        activeDownloads.set(filename, downloadState);

        // 显示进度条容器
        const progressList = document.createElement('div');
        progressList.id = `progress-${filename}`;
        progressList.className = 'chunk-progress-container';
        progressList.style.display = 'block'; // 确保显示
        downloadStatusElement.appendChild(progressList);

        // 计算分片
        const chunks = [];
        for (let start = 0; start < fileSize; start += CHUNK_SIZE) {
          const end = Math.min(start + CHUNK_SIZE - 1, fileSize - 1);
          chunks.push({ start, end });
        }
        downloadState.chunks = chunks;

        // 创建进度条
        chunks.forEach((chunk, index) => {
          const progressBar = document.createElement('div');
          progressBar.className = 'chunk-progress';
          const safeFileName = encodeURIComponent(filename).replace(/%/g, '_');
          progressBar.innerHTML = `
                    <progress value="0" max="100" id="chunk-${safeFileName}-${index}"></progress>
                    <span class="chunk-label" id="chunk-label-${safeFileName}-${index}">分片 ${index + 1}: 0%</span>
                `;
          progressList.appendChild(progressBar);
        });

        // 添加暂停/继续按钮
        const pauseResumeBtn = document.createElement('button');
        pauseResumeBtn.className = 'btn pause-resume-btn';
        pauseResumeBtn.textContent = '暂停';
        pauseResumeBtn.onclick = () => {
          downloadState.paused = !downloadState.paused;
          pauseResumeBtn.textContent = downloadState.paused ? '继续' : '暂停';
        };
        progressList.appendChild(pauseResumeBtn);

        // 开始下载
        await downloadChunks(filename, downloadState);
      }

      // 更新下载速度和时间显示
      function updateDownloadStatus(downloadState) {
        const elapsed = (Date.now() - downloadState.startTime) / 1000;
        const speed = downloadState.downloadedSize / elapsed;
        const speedText = formatFileSize(speed) + '/s';
        const timeText = formatTime(Date.now() - downloadState.startTime);
        $(downloadState.statusElement).text(`下载速度: ${speedText} | 已用时间: ${timeText}`);
      }

      // 下载分片（更新）
      async function downloadChunks(filename, downloadState) {
        const { chunks, downloaded } = downloadState;

        // 更新下载状态的定时器
        const statusInterval = setInterval(() => {
          if (!downloadState.paused) {
            updateDownloadStatus(downloadState);
          }
        }, 1000);

        try {
          while (downloaded.size < chunks.length) {
            if (downloadState.paused) {
              await new Promise((resolve) => setTimeout(resolve, 1000));
              continue;
            }

            const pendingChunks = chunks
              .map((chunk, index) => ({ chunk, index }))
              .filter(({ index }) => !downloaded.has(index))
              .slice(0, MAX_CONCURRENT_CHUNKS);

            if (pendingChunks.length === 0) break;

            const chunkPromises = pendingChunks.map(({ chunk, index }) =>
              downloadChunk(filename, chunk, index, downloadState),
            );

            await Promise.all(chunkPromises);
          }

          // 所有分片下载完成，合并文件
          if (downloaded.size === chunks.length) {
            clearInterval(statusInterval);
            const duration = Date.now() - downloadState.startTime;
            downloadState.statusElement.textContent = `下载完成 | 总耗时: ${formatTime(duration)}`;
            await mergeAndDownload(filename, downloadState);
            activeDownloads.delete(filename);
          }
        } catch (error) {
          console.error('Download failed:', error);
          alert('下载失败，请重试');
          clearInterval(statusInterval);
          downloadState.statusElement.textContent = '下载失败';
          activeDownloads.delete(filename);
        }
      }

      // 下载单个分片（更新）
      async function downloadChunk(filename, { start, end }, index, downloadState) {
        const safeFileName = encodeURIComponent(filename).replace(/%/g, '_');
        const $progressBar = $(`#chunk-${safeFileName}-${index}`);
        const $progressLabel = $(`#chunk-label-${safeFileName}-${index}`);

        // 如果找不到进度条元素，跳过更新进度
        if ($progressBar.length === 0 || $progressLabel.length === 0) {
          console.warn(`Progress elements not found for chunk ${index} of file ${filename}`);
          return;
        }

        try {
          const response = await fetch(`/files/chunk-download/${filename}`, {
            headers: { Range: `bytes=${start}-${end}` },
          });

          if (!response.ok) throw new Error('Chunk download failed');

          const reader = response.body.getReader();
          const contentLength = parseInt(response.headers.get('Content-Length'), 10);
          let receivedLength = 0;
          let lastProgressUpdate = 0;
          const chunks = [];

          function updateProgress(received, total) {
            const now = Date.now();
            // 限制更新频率，避免过于频繁的DOM更新
            if (now - lastProgressUpdate < 100) return;
            lastProgressUpdate = now;

            const progress = (received / total) * 100;
            $progressBar.val(progress);
            $progressLabel.text(`分片 ${index + 1}: ${progress.toFixed(1)}%`);

            // 更新总体下载进度
            downloadState.downloadedSize = received;
            updateDownloadStatus(downloadState);
          }

          while (true) {
            const { done, value } = await reader.read();
            if (done) break;

            chunks.push(value);
            receivedLength += value.length;
            downloadState.downloadedSize += value.length;

            // 更新进度
            updateProgress(receivedLength, contentLength);
          }

          // 合并分片数据
          const blob = new Blob(chunks);
          downloadState.chunks[index] = blob;
          downloadState.downloaded.add(index);

          // 更新完成状态
          $progressBar.val(100);
          $progressLabel.text(`分片 ${index + 1}: 完成`);
        } catch (error) {
          console.error(`分片 ${index + 1} 下载失败:`, error);
          $progressLabel.text(`分片 ${index + 1}: 失败`);
          throw error;
        }
      }

      // 合并并下载完整文件（移到全局）
      async function mergeAndDownload(filename, downloadState) {
        try {
          const blobs = downloadState.chunks.filter((chunk) => chunk instanceof Blob);
          const finalBlob = new Blob(blobs);

          const endTime = Date.now();
          const duration = endTime - downloadState.startTime;
          downloadState.statusElement.textContent = `下载完成 | 总耗时: ${formatTime(duration)}`;

          // 创建下载链接
          const url = URL.createObjectURL(finalBlob);
          const a = document.createElement('a');
          a.href = url;
          a.download = filename;
          document.body.appendChild(a);
          a.click();
          document.body.removeChild(a);
          URL.revokeObjectURL(url);

          // 清理下载相关的DOM元素
          cleanupDownload(filename, downloadState);
        } catch (error) {
          console.error('Error merging and downloading file:', error);
          downloadState.statusElement.textContent = '合并文件失败，请重试';
        }
      }

      // 下载完成后清理（新增）
      function cleanupDownload(filename, downloadState) {
        try {
          const progressList = document.getElementById(`progress-${filename}`);
          if (progressList && progressList.parentNode) {
            progressList.parentNode.removeChild(progressList);
          }
        } catch (error) {
          console.warn('Error cleaning up download elements:', error);
        }
      }

      // 修改普通下载链接处理
      function createRegularDownloadLink(file, statusElement) {
        let startTime;
        let downloadCheckInterval;
        let downloadTimeout;

        const $link = $('<a>', {
          href: file.url,
          class: 'btn',
          text: '普通下载',
        }).on('click', function (e) {
          e.preventDefault();

          if (downloadCheckInterval) clearInterval(downloadCheckInterval);
          if (downloadTimeout) clearTimeout(downloadTimeout);

          startTime = Date.now();
          $(statusElement).text('开始下载...');

          $.ajax({
            url: file.url,
            method: 'HEAD',
          })
            .then(function (_, __, response) {
              const contentLength = response.getResponseHeader('content-length');

              const $downloadLink = $('<a>', {
                href: file.url,
                css: { display: 'none' },
              }).appendTo('body');

              $downloadLink[0].click();
              $downloadLink.remove();

              downloadCheckInterval = setInterval(() => {
                const elapsed = Date.now() - startTime;
                $(statusElement).text(`下载中... | 已用时间: ${formatTime(elapsed)}`);
              }, 1000);

              const estimatedTimeInSeconds = Math.ceil(contentLength / (1024 * 1024));
              downloadTimeout = setTimeout(() => {
                clearInterval(downloadCheckInterval);
                const endTime = Date.now();
                const duration = endTime - startTime;
                $(statusElement).text(`下载完成 | 总耗时: ${formatTime(duration)}`);
              }, estimatedTimeInSeconds * 1000);
            })
            .fail(function (error) {
              console.error('Error starting download:', error);
              $(statusElement).text('下载出错，请重试');
              if (downloadCheckInterval) clearInterval(downloadCheckInterval);
              if (downloadTimeout) clearTimeout(downloadTimeout);
            });
        });

        return $link;
      }

      // 修改流式下载处理
      function createStreamLink(file, statusElement) {
        return $('<a>', {
          href: `/files/stream/${file.filename}`,
          class: 'btn',
          text: '在线预览',
          target: '_blank',
        }).on('click', function () {
          const startTime = Date.now();
          $(statusElement).text('开始加载...');

          $.ajax({
            url: this.href,
            xhr: function () {
              const xhr = new XMLHttpRequest();
              xhr.responseType = 'blob';
              return xhr;
            },
          })
            .then(function () {
              const endTime = Date.now();
              const duration = endTime - startTime;
              $(statusElement).text(`加载完成 | 总耗时: ${formatTime(duration)}`);
            })
            .fail(function (error) {
              $(statusElement).text('加载失败');
              console.error('Stream error:', error);
            });

          return true; // 允许浏览器继续处理链接
        });
      }

      /**
       * 启动多线程下载
       * @param {string} filename - 文件名
       * @param {number} fileSize - 文件大小
       * @param {HTMLElement} downloadStatusElement - 下载状态显示元素
       */
      function startMultiThreadedDownload(filename, fileSize, downloadStatusElement) {
        const downloadTask = async () => {
          const manager = new ChunkDownloadManager(filename, fileSize, downloadStatusElement);
          await manager.start();
        };

        downloadQueue.add(downloadTask);
      }

      // ================ 页面加载完成后的初始化 ================
      $(document).ready(function () {
        const $uploadForm = $('#uploadForm');
        const $fileInput = $('#fileInput');
        const $uploadProgress = $('#uploadProgress');
        const $uploadStatus = $('#uploadStatus');
        const $refreshButton = $('#refreshButton');
        const $fileList = $('#fileList');

        // 页面加载时获取文件列表
        fetchFileList();

        // 处理文件上传
        $uploadForm.on('submit', function (e) {
          e.preventDefault();

          const file = $fileInput[0].files[0];
          if (!file) {
            $uploadStatus.text('Por favor seleccione un archivo');
            return;
          }

          const maxSize = 1024 * 1024 * 1024; // 1GB
          if (file.size > maxSize) {
            $uploadStatus.text(
              'El archivo es demasiado grande. El tamaño máximo permitido es 1GB.',
            );
            return;
          }

          const formData = new FormData();
          formData.append('file', file);

          $uploadProgress.show().val(0);
          $uploadStatus.text('Iniciando carga...');

          $.ajax({
            url: '/files/upload',
            method: 'POST',
            data: formData,
            processData: false,
            contentType: false,
            timeout: 60000,
            xhr: function () {
              const xhr = new XMLHttpRequest();
              xhr.upload.onprogress = function (e) {
                if (e.lengthComputable) {
                  const percentComplete = (e.loaded / e.total) * 100;
                  $uploadProgress.val(percentComplete);
                  $uploadStatus.text(`Cargando: ${Math.round(percentComplete)}%`);
                }
              };
              return xhr;
            },
          })
            .done(function () {
              $uploadStatus.text('Archivo cargado exitosamente!');
              $uploadForm[0].reset();
              fetchFileList();
            })
            .fail(function (xhr, status, error) {
              if (status === 'timeout') {
                $uploadStatus.text(
                  'La carga tomó demasiado tiempo. Por favor, inténtelo de nuevo.',
                );
              } else {
                $uploadStatus.text(`Error al cargar: ${error || 'Error del servidor'}`);
                console.error('Error de carga:', xhr.responseText);
              }
            });
        });

        // 刷新按钮点击事件
        $refreshButton.on('click', fetchFileList);

        // 获取文件列表
        function fetchFileList() {
          $.getJSON('/files/list')
            .done(function (files) {
              $fileList.empty();

              if (files.length === 0) {
                $fileList.html('<li>No hay archivos disponibles</li>');
                return;
              }

              files.forEach(function (file) {
                const $downloadStatus = $('<div>', { class: 'download-status' });

                const $fileItem = $('<li>', { class: 'file-item' }).append(
                  $('<div>', { class: 'file-item-header' }).append(
                    $('<div>', { class: 'file-info' }).append(
                      $('<span>', { class: 'file-name', text: file.filename }),
                      $('<span>', { class: 'file-size', text: formatFileSize(file.size) }),
                    ),
                    $('<div>', { class: 'file-actions' }).append(
                      createRegularDownloadLink(file, $downloadStatus),
                      createStreamLink(file, $downloadStatus),
                      $('<button>', {
                        class: 'btn',
                        text: '快速下载',
                        click: () =>
                          startMultiThreadedDownload(file.filename, file.size, $downloadStatus),
                      }),
                    ),
                  ),
                  $downloadStatus,
                );

                $fileList.append($fileItem);
              });
            })
            .fail(function (error) {
              $fileList.html(`<li>Error: ${error.statusText || error.message}</li>`);
            });
        }
      });
    </script>
    <!-- JavaScript代码结束 -->
  </body>
</html>
